﻿namespace DomainServices.Tools
{
    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Security;
    using System.ServiceModel.DomainServices;
    using System.Text;

    internal static class AssemblyUtilities
    {
        private static ConcurrentDictionary<string, Assembly> loadedAssemblyNames;

        private static Assembly CurrentDomain_AssemblyResolveEventHandler(object sender, ResolveEventArgs args)
        {
            Assembly assembly = null;
            if (string.IsNullOrEmpty(args.Name) || (loadedAssemblyNames == null))
            {
                return assembly;
            }
            return loadedAssemblyNames.GetOrAdd(args.Name, name => Enumerable.FirstOrDefault<Assembly>(AppDomain.CurrentDomain.GetAssemblies(), a => a.FullName == name));
        }

        internal static IEnumerable<Type> GetExportedTypes(Assembly assembly, ILogger logger)
        {
            Type[] exportedTypes = null;
            try
            {
                exportedTypes = assembly.GetExportedTypes();
            }
            catch (Exception exception)
            {
                if (exception.IsFatal())
                {
                    throw;
                }
                if (((exception is TypeLoadException) || (exception is FileNotFoundException)) || ((exception is FileLoadException) || (exception is BadImageFormatException)))
                {
                    if ((logger != null) && !IsAssemblyMsCorlib(assembly.GetName()))
                    {
                        logger.LogMessage(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Assembly_Load_Type_Error, new object[] { assembly.FullName, exception.Message }));
                    }
                    return new Type[0];
                }
                ReflectionTypeLoadException exception2 = exception as ReflectionTypeLoadException;
                if (exception2 == null)
                {
                    throw;
                }
                exportedTypes = exception2.Types;
                if (logger != null)
                {
                    StringBuilder builder = new StringBuilder();
                    foreach (Exception exception3 in exception2.LoaderExceptions)
                    {
                        builder.AppendLine(exception3.Message);
                    }
                    logger.LogMessage(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Failed_To_Load, new object[] { assembly.FullName, builder.ToString() }));
                }
                return (from t in exportedTypes
                    where t != null
                    select t);
            }
            return exportedTypes;
        }

        internal static bool IsAssemblyMsCorlib(AssemblyName assemblyName)
        {
            return ((string.Compare(assemblyName.Name, "mscorlib", StringComparison.OrdinalIgnoreCase) == 0) && System.ServiceModel.DomainServices.TypeUtility.IsSystemAssembly(assemblyName.FullName));
        }

        internal static Assembly LoadAssembly(AssemblyName assemblyName, ILogger logger)
        {
            Assembly assembly = null;
            try
            {
                assembly = Assembly.Load(assemblyName);
            }
            catch (Exception exception)
            {
                if ((!(exception is FileNotFoundException) && !(exception is FileLoadException)) && ((!(exception is PathTooLongException) && !(exception is BadImageFormatException)) && !(exception is SecurityException)))
                {
                    throw;
                }
                if (logger != null)
                {
                    logger.LogMessage(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Assembly_Load_Error, new object[] { assemblyName, exception.Message }));
                }
                return assembly;
            }
            return assembly;
        }

        internal static Assembly LoadAssembly(string assemblyFileName, ILogger logger)
        {
            Assembly assembly = null;
            try
            {
                assembly = LoadAssembly(AssemblyName.GetAssemblyName(assemblyFileName), null);
                if (assembly != null)
                {
                    return assembly;
                }
                assembly = Assembly.LoadFrom(assemblyFileName);
            }
            catch (Exception exception)
            {
                if ((!(exception is FileNotFoundException) && !(exception is FileLoadException)) && ((!(exception is PathTooLongException) && !(exception is BadImageFormatException)) && !(exception is SecurityException)))
                {
                    throw;
                }
                if (logger != null)
                {
                    logger.LogMessage(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Assembly_Load_Error, new object[] { assemblyFileName, exception.Message }));
                }
                return assembly;
            }
            return assembly;
        }

        internal static Assembly ReflectionOnlyLoad(AssemblyName assemblyName, IEnumerable<string> assemblySearchPaths, ILogger logger)
        {
            Assembly assembly = null;
            string message = null;
            try
            {
                assembly = Assembly.ReflectionOnlyLoad(assemblyName.FullName);
            }
            catch (Exception exception)
            {
                if ((!(exception is FileNotFoundException) && !(exception is FileLoadException)) && ((!(exception is PathTooLongException) && !(exception is BadImageFormatException)) && !(exception is SecurityException)))
                {
                    throw;
                }
                message = exception.Message;
            }
            if ((assembly == null) && (assemblySearchPaths != null))
            {
                assembly = ReflectionOnlyLoadFromSearchPaths(assemblyName, assemblySearchPaths);
            }
            if (((assembly == null) && !string.IsNullOrEmpty(message)) && (logger != null))
            {
                logger.LogMessage(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Assembly_Load_Error, new object[] { assemblyName, message }));
            }
            return assembly;
        }

        internal static Assembly ReflectionOnlyLoadFrom(string assemblyFileName, ILogger logger)
        {
            Assembly assembly = null;
            try
            {
                assembly = Assembly.ReflectionOnlyLoadFrom(assemblyFileName);
            }
            catch (Exception exception)
            {
                if ((!(exception is FileNotFoundException) && !(exception is FileLoadException)) && ((!(exception is PathTooLongException) && !(exception is BadImageFormatException)) && !(exception is SecurityException)))
                {
                    throw;
                }
                if (logger != null)
                {
                    logger.LogMessage(string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Assembly_Load_Error, new object[] { assemblyFileName, exception.Message }));
                }
                return assembly;
            }
            return assembly;
        }

        internal static Assembly ReflectionOnlyLoadFromSearchPaths(AssemblyName assemblyName, IEnumerable<string> assemblySearchPaths)
        {
            string name = assemblyName.Name;
            foreach (string str2 in assemblySearchPaths)
            {
                string path = Path.Combine(str2, name) + ".dll";
                if (File.Exists(path))
                {
                    Assembly assembly = ReflectionOnlyLoadFrom(path, null);
                    if (assembly != null)
                    {
                        return assembly;
                    }
                }
            }
            return null;
        }

        internal static bool ReflectionOnlyLoadReferences(Assembly assembly, IEnumerable<string> assemblySearchPaths, Dictionary<string, Assembly> loadedAssemblies, bool recursive, ILogger logger)
        {
            bool flag = true;
            loadedAssemblies[assembly.FullName] = assembly;
            foreach (AssemblyName name in assembly.GetReferencedAssemblies())
            {
                if (!IsAssemblyMsCorlib(name))
                {
                    Assembly assembly2 = null;
                    if (!loadedAssemblies.TryGetValue(name.FullName, out assembly2))
                    {
                        assembly2 = ReflectionOnlyLoad(name, assemblySearchPaths, logger);
                        loadedAssemblies[name.FullName] = assembly2;
                        if ((assembly2 != null) && recursive)
                        {
                            if (!ReflectionOnlyLoadReferences(assembly2, assemblySearchPaths, loadedAssemblies, recursive, logger))
                            {
                                flag = false;
                            }
                        }
                        else
                        {
                            flag = false;
                        }
                    }
                }
            }
            return flag;
        }

        internal static void SetAssemblyResolver(IEnumerable<Assembly> assemblies)
        {
            ConcurrentDictionary<string, Assembly> dictionary = new ConcurrentDictionary<string, Assembly>(StringComparer.OrdinalIgnoreCase);
            foreach (Assembly assembly in assemblies)
            {
                dictionary[assembly.FullName] = assembly;
            }
            loadedAssemblyNames = dictionary;
            AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(AssemblyUtilities.CurrentDomain_AssemblyResolveEventHandler);
            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(AssemblyUtilities.CurrentDomain_AssemblyResolveEventHandler);
        }
    }
}

